#ifndef COCKPITAVIAGORIZONT_H
#define COCKPITAVIAGORIZONT_H

#include "CockpitBar.h"

namespace AviagorizontUtils {
    template <typename Float>
    struct PitchRoll
    {
        Float pitch, roll;
    };

    template <typename Float>
    Float degreesToRadians(Float degrees)
    {
        return degrees * M_PI / 180.0;
    }
}

template <typename Float>
class CockpitAviagorizont : public CockpitBar<AviagorizontUtils::PitchRoll<Float>>
{
public:
    CockpitAviagorizont(AviagorizontUtils::PitchRoll<Float> value)
    : CockpitBar<AviagorizontUtils::PitchRoll<Float>>(value
                        , [](const AviagorizontUtils::PitchRoll<Float> & value) -> AviagorizontUtils::PitchRoll<Float>
                        {
                            return { std::clamp(value.pitch, Float(-90), Float(90)), CockpitBarUtils::modAbs180(-value.roll) };
                        }
                        )
    {}

protected:
    void paintEvent(QPaintEvent * event) override
    {
        CockpitBar<AviagorizontUtils::PitchRoll<Float>>::paintEvent(event);

        QPainter painter(this);

        const QPen black_pen_1(Qt::black, 1);
        const QPen black_pen_3(Qt::black, 3);
        const QPen black_pen_5(Qt::black, 5);
        const QBrush cyan_brush(Qt::cyan);
        const QBrush yellow_brush(Qt::yellow);
        const QBrush empty_brush;

        painter.setPen(black_pen_3);
        painter.setBrush(cyan_brush);
        _drawBackground(painter);

        painter.setPen(black_pen_1);
        painter.setBrush(yellow_brush);
        painter.setFont(QFont(_TEXT_FONT_FAMILY));
        _drawPitchIndicator(painter);
                
        // painter.setFont(QFont("monospace", 20));
        painter.setPen(black_pen_5);
        painter.setBrush(empty_brush);
        _drawRollIndicator(painter);//, QPen(Qt::darkGreen));

        painter.setPen(black_pen_3);
        painter.setBrush(empty_brush);
        _drawBackground(painter);
    }

private:
    static constexpr Float _SIDE_PADDING_MULTIPLIER = 1.0 / 20;
    static const QString _TEXT_FONT_FAMILY;

    void _drawBackground(QPainter & painter)
    {
        const QPointF center = CockpitBar<AviagorizontUtils::PitchRoll<Float>>::center();
        const Float min_side = std::min(this->width(), this->height());
        const Float side_size = min_side * (1 - 2 * this->_SIDE_PADDING_MULTIPLIER);
        const QRectF indicator_rect = { center.x() - side_size / 2, center.y() - side_size / 2, side_size, side_size };

        painter.drawRect(indicator_rect);
    }

    void _drawPitchIndicator(QPainter & painter)
    {
        const QPointF center = CockpitBar<AviagorizontUtils::PitchRoll<Float>>::center();
        const Float min_side = std::min(this->width(), this->height());
        const Float side_size = (1 - 2 * _SIDE_PADDING_MULTIPLIER) * min_side;
        const Float side_size_2 = side_size / 2.;
        const Float side_size_8 = side_size / 8.;
        const Float _3_side_size_8 = 3. * side_size / 8.;

        const Float pitch_value = this->value().pitch;
        const int ceiled_pitch = std::ceil(pitch_value);
        const int ceiled_10_pitch = ceiled_pitch - ceiled_pitch % 10 + (ceiled_pitch < 0 ? 0 : 10);
        const Float line_left_x = center.x() - _3_side_size_8;
        const Float line_right_x = center.x() + _3_side_size_8;

        auto pitch_y = [side_size_2, pitch_value, center](Float pitch)
        {
            return center.y() - side_size_2 * std::sin(AviagorizontUtils::degreesToRadians(pitch - pitch_value));
        };

        painter.drawRect(QRectF(
                            QPointF(center.x() - side_size_2, pitch_y(0))
                            , QPointF(center.x() + side_size_2, center.y() + side_size_2)
                            ));

        const int top_pitch_bound = CockpitBar<AviagorizontUtils::PitchRoll<Float>>::restrictionPolicy()({pitch_value + 60, 0}).pitch;
        for (int top_pitch = ceiled_10_pitch; top_pitch <= top_pitch_bound; top_pitch += 10)
        {
            const Float top_pitch_y = pitch_y(top_pitch);
            painter.drawLine(line_left_x, top_pitch_y, line_right_x, top_pitch_y);

            const Float next_top_pitch_y = pitch_y(top_pitch + 10);
            QString top_pitch_string = QString::number(top_pitch);

            const QRectF left_text_rect = { line_left_x - side_size_8
                                            , next_top_pitch_y + (top_pitch_y - next_top_pitch_y) / 2.
                                            , side_size_8
                                            , top_pitch_y - next_top_pitch_y
                                            };
            const QRectF right_text_rect = { line_right_x, left_text_rect.y(), left_text_rect.width(), left_text_rect.height() };

            painter.setFont(CockpitBarUtils::fitTextToRectF(top_pitch_string
                                                            , painter.font()
                                                            , QRectF{ 0, 0, left_text_rect.width(), left_text_rect.height() }
                                                            ));
            painter.drawText(left_text_rect, Qt::AlignCenter, top_pitch_string);
            painter.drawText(right_text_rect, Qt::AlignCenter, top_pitch_string);
        }

        const int bottom_pitch_bound = CockpitBar<AviagorizontUtils::PitchRoll<Float>>::restrictionPolicy()({pitch_value - 60, 0}).pitch;
        for (int bottom_pitch = ceiled_10_pitch - 10; bottom_pitch_bound <= bottom_pitch; bottom_pitch -= 10)
        {
            const Float bottom_pitch_y = pitch_y(bottom_pitch);
            painter.drawLine(line_left_x, bottom_pitch_y, line_right_x, bottom_pitch_y);

            const Float prev_bottom_pitch_y = pitch_y(bottom_pitch + 10);
            QString bottom_pitch_string = QString::number(bottom_pitch);

            const QRectF left_text_rect = { line_left_x - side_size_8
                                            , prev_bottom_pitch_y + (bottom_pitch_y - prev_bottom_pitch_y) / 2.
                                            , side_size_8
                                            , bottom_pitch_y - prev_bottom_pitch_y
                                            };
            const QRectF right_text_rect = { line_right_x, left_text_rect.y(), left_text_rect.width(), left_text_rect.height() };

            painter.setFont(CockpitBarUtils::fitTextToRectF(bottom_pitch_string
                                                            , painter.font()
                                                            , QRectF{ 0, 0, left_text_rect.width(), left_text_rect.height() }
                                                            ));
            painter.drawText(left_text_rect, Qt::AlignCenter, bottom_pitch_string);
            painter.drawText(right_text_rect, Qt::AlignCenter, bottom_pitch_string);
        }

        painter.setPen(QPen(Qt::black, 3));
        painter.drawLine(line_left_x, center.y(), line_left_x + side_size_8, center.y() + side_size_8);
        painter.drawLine(line_left_x, center.y(), line_left_x + side_size_8, center.y() - side_size_8);
        painter.drawLine(line_right_x, center.y(), line_right_x - side_size_8, center.y() + side_size_8);
        painter.drawLine(line_right_x, center.y(), line_right_x - side_size_8, center.y() - side_size_8);
    }

    void _drawRollIndicator(QPainter & painter)//, const QPen & number_pen)
    {
        const QPointF center = CockpitBar<AviagorizontUtils::PitchRoll<Float>>::center();
        const Float min_side = std::min(this->width(), this->height());
        const Float side_size = (1 - 2 * _SIDE_PADDING_MULTIPLIER) * min_side;
        const Float side_size_4 = side_size / 4.;
        const Float side_size_8 = side_size / 8.;
        const Float side_size_16 = side_size / 16.;

        const Float roll = std::round(this->value().roll);
        const Float angle_radians = AviagorizontUtils::degreesToRadians(roll);
        
        const QPointF arrow_point = { center.x() + std::cos(angle_radians) * side_size_4
                                    , center.y() - std::sin(angle_radians) * side_size_4
                                    };
        const QPointF mirror_point = { center.x() - std::cos(angle_radians) * side_size_4
                                        , center.y() + std::sin(angle_radians) * side_size_4
                                        };
        const QPointF tail_point = { center.x() + std::cos(angle_radians + M_PI_2) * side_size_8
                                    , center.y() - std::sin(angle_radians + M_PI_2) * side_size_8
                                    };
        const QRectF body_rect = { center.x() - side_size_16
                                    , center.y() - side_size_16
                                    , side_size_8
                                    , side_size_8
                                    };
        
        painter.drawLine(arrow_point, mirror_point);
        painter.drawEllipse(body_rect);
        painter.drawLine(center, tail_point);

        // painter.setPen(number_pen);
        // painter.drawText(arrow_point, QString::number(-roll));
    }
};

template <typename Float>
const QString CockpitAviagorizont<Float>::_TEXT_FONT_FAMILY = "monospace";

#endif // COCKPITAVIAGORIZONT_H
